package com.example.walkera.rkipcamerademo;


import java.io.File;
import java.io.IOException;
import java.lang.ref.WeakReference;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
//import android.os.SystemProperties;

import com.example.walkera.rkipcamerademo.ICameraCrashService;
import com.example.walkera.rkipcamerademo.CameraManager.CameraOpenErrorCallback;
import com.example.walkera.rkipcamerademo.CameraManager.CameraProxy;
import com.example.walkera.rkipcamerademo.CameraUtil.RecordState;

import android.annotation.TargetApi;
import android.app.Service;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.hardware.Camera.CameraInfo;
import android.hardware.Camera.Parameters;
import android.hardware.Camera.Size;
import android.hardware.Sensor;
import android.hardware.SensorManager;
import android.media.CamcorderProfile;
import android.media.CameraProfile;
import android.media.MediaRecorder;
import android.os.Build;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.os.RemoteException;
import android.os.SystemClock;

import android.util.DisplayMetrics;
import android.util.Log;
import android.widget.Toast;



public class CameraCrashService extends Service {

	private static String TAG = "CameraCrashService";

	private static int times = 0;
	private  Context mContext = null;
	private static int MSG_ID_BASE = 100;
	private Thread mMsgThread;
	private boolean mThreadRunning = true;
    private static String MEDIA_TYPE_IMAGE = "IMAGE";
    private static String MEDIA_TYPE_VIDEO = "VIDEO";
	private  CameraProxy mCameraDevice;
	private static final int IDLE_DELAY  = 1001;
	private static final int MESSAGE_DELAY  = 60000*2;
	private  RecordState mState = RecordState.NONE;
	private int mHDMIIN = 1;
	
    private int mCameraId;
	
	private int mServiceStartId = -1;
	private boolean mServiceInUse = false;
	private int mServiceIsOpen = 0;
	private final IBinder mBinder = new MyBinder(this);
	private final CameraErrorCallback mErrorCallback = new CameraErrorCallback();
	private static final int TRACK_ENDED = 1;
	private static final int RELEASE_WAKELOCK = 2;
	private static final int SERVER_DIED = 3;
	private static final int FOCUSCHANGE = 4;
	private static final int FADEDOWN = 5;
	private static final int FADEUP = 6;
	private static final int TRACK_WENT_TO_NEXT = 7;
	private static final int MAX_HISTORY_SIZE = 100;


	private int mTargetWidth = 1920;
	private int mTargetHeight = 1080;
	private SharedPreferences mPreferences;
	private BroadcastReceiver mUnmountReceiver = null;
	private boolean mQueueIsSaveable = true;

	private final String resolution = "sys.hdmiin.resolution";//sys_graphic
	private final String display = "sys.hdmiin.display"; //sys_graphic
	
    private int mDesiredPreviewHeight;

    private int mDesiredPreviewWidth;
	private static HashMap<Integer,MediaRecorder> mMediaRecorderMap = new HashMap<Integer,MediaRecorder>();

	@Override
	public void onCreate() {
		Log.e(TAG, "CameraCrashService onCreate()");

		super.onCreate();
		mContext = this;
		Message msg = mDelayedStopHandler.obtainMessage();
		mDelayedStopHandler.sendMessageDelayed(msg, IDLE_DELAY);
		//
		mPreferences = getSharedPreferences("Music", MODE_WORLD_READABLE | MODE_WORLD_WRITEABLE);

		//获取后置摄像头id
		int cameraId = CameraHolder.instance().getBackCameraId();
		mCameraId = cameraId;
		if(mCameraDevice == null){
		     mCameraDevice = CameraHolder.instance().open(mMainrHandler,mCameraId, mCameraOpenErrorCallback);
		     readVideoPreferences();
		     CameraInfo[] cameraInfo = CameraHolder.instance().getCameraInfo();
		     for (int i = 0; i < cameraInfo.length; i++) {
				System.out.println(cameraInfo[i]);
			}
		  }
		
		//new Thread(mScanHdmiIn).start();
    
		mThreadRunning = true;
	}

	
	
	
	private void saveQueue(boolean full) {
		if (!mQueueIsSaveable) {
			return;
		}
		Editor ed = mPreferences.edit();
		ed.putInt("state", mState.value);
		ed.putInt("isopen", mServiceIsOpen);
		ed.putInt("width", mTargetWidth);
		ed.putInt("height", mTargetHeight);
		ed.putInt("ServiceStartId",mServiceStartId);
		ed.commit();
	}
	
	private void reloadQueue() {

		if (mPreferences.contains("state")) {

			int state = mPreferences.getInt("state", RecordState.NONE.value);
			mState = RecordState.valueOf(state);
		}
		if (mPreferences.contains("isopen")) {

			int isopen = mPreferences.getInt("isopen", -1);
			mServiceIsOpen = isopen;
		}
		mServiceStartId = mPreferences.getInt("ServiceStartId", 0);
		mTargetWidth =  mPreferences.getInt("width", 0);
		mTargetHeight =  mPreferences.getInt("height", 0);
	}

	@Override
	public int onStartCommand(Intent intent, int flags, int startId) {
	
		if( null != intent){
		    
		    
		    Log.e(TAG, "CameraCrashService onStart()" + startId);
	        mServiceStartId = startId;

	        mDelayedStopHandler.removeCallbacksAndMessages(null);

	        mServiceIsOpen = 1;
	        mDelayedStopHandler.removeCallbacksAndMessages(null);
	        Message msg = mDelayedStopHandler.obtainMessage();
	        mDelayedStopHandler.sendMessageDelayed(msg, IDLE_DELAY);
		}
		
		return START_STICKY;
	}

	@Override
	public void onDestroy() {
	    loop = false;
		Log.e(TAG, "CameraCrashService onDestroy()");

		
		if(mCameraDevice!= null){
		    mCameraDevice.release();
		    closeCamera();
			mCameraDevice=null;
		}

		mState = RecordState.NONE;
		saveQueue(true);
		//mCrashGsensorTest.onPause();
		mDelayedStopHandler.removeCallbacksAndMessages(null);
		 mMainrHandler.removeCallbacksAndMessages(null);
		if (mUnmountReceiver != null) {
			unregisterReceiver(mUnmountReceiver);
			mUnmountReceiver = null;
		}
		super.onDestroy();
	}

	@Override
	public IBinder onBind(Intent intent) {
		Log.e(TAG, "Service(Airplay) onBind()");
		 mServiceInUse = true;
		 mDelayedStopHandler.removeCallbacksAndMessages(null);
		return mBinder;
	}
	 @Override
	 public void onRebind(Intent intent) {
	          mServiceInUse = true;
	          mDelayedStopHandler.removeCallbacksAndMessages(null);
	 } 
	@Override
	public boolean onUnbind(Intent intent) {
		Log.e(TAG, "Service(CameraCrashService) onUnbind()"+intent);
		mServiceInUse = false;

		if (mState != RecordState.NONE || mServiceInUse) {
			// something is currently playing, or will be playing once
			// an in-progress action requesting audio focus ends, so don't stop
			// the service now.
			return true;
		}

		// If there is a playlist but playback is paused, then wait a while
		// before stopping the service, so that pause/resume isn't slow.
		// Also delay stopping the service if we're transitioning between
		// tracks.
		if (mMainrHandler.hasMessages(TRACK_WENT_TO_NEXT)) {
			Message msg = mDelayedStopHandler.obtainMessage();
			mDelayedStopHandler.sendMessageDelayed(msg, IDLE_DELAY);
			return true;
		}
		saveQueue(true);
		stopSelf(mServiceStartId);
		return true;
	}

	private void gotoIdleState() {
		mDelayedStopHandler.removeCallbacksAndMessages(null);
		Message msg = mDelayedStopHandler.obtainMessage();
		mDelayedStopHandler.sendMessageDelayed(msg, IDLE_DELAY);
		stopForeground(true);
	}

	private Handler mDelayedStopHandler = new Handler() {
		@Override
		public void handleMessage(Message msg) {
			// Check again to make sure nothing is playing right now
			if (mState != RecordState.NONE || mServiceInUse) {
				return;
			}
			saveQueue(true);
			// save the queue again, because it might have changed
			// since the user exited the music app (because of
			// party-shuffle or because the play-position changed)
			stopSelf(mServiceStartId);
		}
	};

	private Handler mMainrHandler = new Handler() {
		float mCurrentVolume = 1.0f;

		@Override
		public void handleMessage(Message msg) {
			switch (msg.what) {

			case SERVER_DIED:
				/*
				 * if (mIsSupposedToBePlaying) { gotoNext(true); } else { // the
				 * server died when we were idle, so just // reopen the same
				 * song (it will start again // from the beginning though when
				 * the user // restarts) openCurrentAndNext(); }
				 */
				break;
			case TRACK_WENT_TO_NEXT:
				/*
				 * mPlayPos = mNextPlayPos;
				 * 
				 * 
				 * updateNotification(); setNextTrack();
				 */
				
				//System.out.println("=================================================TRACK_WENT_TO_NEXT");
				if(mState == RecordState.NONE) break;
				
				//resetMediaRecorder();

				mMainrHandler.sendEmptyMessageDelayed(TRACK_WENT_TO_NEXT,MESSAGE_DELAY);
				break;
			case TRACK_ENDED:
				/*
				 * if (mRepeatMode == REPEAT_CURRENT) { seek(0); play(); } else
				 * { gotoNext(false); }
				 */
				System.out.println("=================================================TRACK_ENDED");
			default:
				break;
			}
		}
	};
	
	Handler mHander = new Handler(){

        @Override
        public void handleMessage(Message msg) {
            // TODO Auto-generated method stub
            //super.handleMessage(msg);
            switch (msg.what) {
                case 1:
                    //stopPreview();
                    StartPreview();
                    break;
				case  2:
					reOpenCamera();
					StartPreview();
					break;
                default:
                    break;
            }
        }
	    
	};
	boolean loop = true;
	Runnable mScanHdmiIn = new Runnable() {
        
        @Override
        public void run() {
            while(loop){
//                if( ("1".equals(SystemProperties.get(resolution,"1"))&&1 != mHDMIIN)
//						||("2".equals(SystemProperties.get(resolution,"1"))&& 2!= mHDMIIN)){
//                    Log.i(TAG, "hdmi in change!");
//                    mHander.sendEmptyMessage(1);
//                    SystemClock.sleep(1000);
//                }
//				if(("0".equals(SystemProperties.get(display,"0")))){
//					//Log.i(TAG, "black display");
//					times++;
//					if(times > 5) {
//						Log.i(TAG, "black display");
//						mHander.sendEmptyMessage(2);
//						times = 0;
//                        SystemClock.sleep(2000);
//					}
//					SystemClock.sleep(400);
//				}
				SystemClock.sleep(1000);
                
            }
            
        }
    };

    private CamcorderProfile mProfile;

    private Parameters mParameters;

	private void sendStickBroast(String action){
		Intent i = new Intent(action);
		sendBroadcast(i);
	}

	private void reOpenCamera(){
		closeCamera();
		if(mCameraDevice == null){
			mCameraDevice = CameraHolder.instance().open(mMainrHandler,mCameraId, mCameraOpenErrorCallback);
			readVideoPreferences();
			CameraInfo[] cameraInfo = CameraHolder.instance().getCameraInfo();
			for (int i = 0; i < cameraInfo.length; i++) {
				System.out.println(cameraInfo[i]);
			}
		}
	}
	
	  private void readVideoPreferences() {
	        // The preference stores values from ListPreference and is thus string type for all values.
	        // We need to convert it to int manually.
//	        int defaultQuality = CamcorderProfile.QUALITY_1080P;
//	        mHDMIIN = 1;
//	        if("2".equals(SystemProperties.get(resolution,"1"))){
	            int defaultQuality = CamcorderProfile.QUALITY_720P;
	            mHDMIIN = 2;
	            Log.i(TAG, "720p");
//            }

            //int videoQuality = CameraUtil.getSupportedHighestVideoQuality(mCameraId, defaultQuality);
	        int quality = Integer.valueOf(defaultQuality);
	       
            Log.i(TAG, "QUALITY"+ quality); 
	        mProfile = CamcorderProfile.get(mCameraId, quality);
	        getDesiredPreviewSize();
	    }
	  
	  @TargetApi(Build.VERSION_CODES.HONEYCOMB)
	    private void getDesiredPreviewSize() {
	        if (mCameraDevice == null) {
	            return;
	        }
	        mParameters = mCameraDevice.getParameters();
	        if (mParameters.getSupportedVideoSizes() == null) {
	            mDesiredPreviewWidth = mProfile.videoFrameWidth;
	            mDesiredPreviewHeight = mProfile.videoFrameHeight;
	        } else { // Driver supports separates outputs for preview and video.
	            List<Size> sizes = mParameters.getSupportedPreviewSizes();
	            Size preferred = mParameters.getPreferredPreviewSizeForVideo();
	            int product = preferred.width * preferred.height;
	            Iterator<Size> it = sizes.iterator();
	            // Remove the preview sizes that are not preferred.
	            while (it.hasNext()) {
	                Size size = it.next();
	                if (size.width * size.height > product) {
	                    it.remove();
	                }
	            }
	            DisplayMetrics dm = new DisplayMetrics();
                dm = getResources().getDisplayMetrics(); 
	            Size optimalSize = CameraUtil.getOptimalPreviewSize(dm, sizes,
	                    (double) mProfile.videoFrameWidth / mProfile.videoFrameHeight);
	            mDesiredPreviewWidth = optimalSize.width;
	            mDesiredPreviewHeight = optimalSize.height;
	        }
	        Log.v(TAG, "mDesiredPreviewWidth=" + mDesiredPreviewWidth +
	                ". mDesiredPreviewHeight=" + mDesiredPreviewHeight);
	    }
	

	public void StartPreview() {
		if (mCameraDevice != null ) {
			mCameraDevice.stopPreview();
			readVideoPreferences();
			try {
				 mCameraDevice.setErrorCallback(mErrorCallback);
				 mParameters.setPreviewSize(mDesiredPreviewWidth, mDesiredPreviewHeight);
				 int[] fpsRange = CameraUtil.getMaxPreviewFpsRange(mParameters);
			        if (fpsRange.length > 0) {
			            mParameters.setPreviewFpsRange(
			                    fpsRange[Parameters.PREVIEW_FPS_MIN_INDEX],
			                    fpsRange[Parameters.PREVIEW_FPS_MAX_INDEX]);
			        } else {
			            mParameters.setPreviewFrameRate(mProfile.videoFrameRate);
			        }
			        mParameters.set("recording-hint","true");
			        
			        String vstabSupported = mParameters.get("video-stabilization-supported");
			        if ("true".equals(vstabSupported)) {
			            mParameters.set("video-stabilization", "true");
			        }
			        
			        List<Size> supported = mParameters.getSupportedPictureSizes();
			        Size optimalSize = CameraUtil.getOptimalVideoSnapshotPictureSize(supported,
			                (double) mDesiredPreviewWidth / mDesiredPreviewHeight);
			        Size original = mParameters.getPictureSize();
			        if (!original.equals(optimalSize)) {
			            mParameters.setPictureSize(optimalSize.width, optimalSize.height);
			        }
			        Log.v(TAG, "Video snapshot size is " + optimalSize.width + "x" +
			                optimalSize.height);

			        // Set JPEG quality.
			        int jpegQuality = CameraProfile.getJpegEncodingQualityParameter(mCameraId, CameraProfile.QUALITY_HIGH);
			        mParameters.setJpegQuality(jpegQuality);

			        mCameraDevice.setParameters(mParameters);
			        // Keep preview size up to date.
			        mParameters = mCameraDevice.getParameters();

				mCameraDevice.setPreviewDisplay(CameraHolder.instance().getHolder());
			} catch (Exception ex) {
				ex.printStackTrace();
			}
			try{
			mCameraDevice.startPreview();
			}
			catch(Exception e){
			    e.printStackTrace();
			    closeCamera();
			}
		}

	}

	 private void closeCamera() {
	        Log.v(TAG, "closeCamera");
	        if (mCameraDevice == null) {
	            Log.d(TAG, "already stopped.");
	            return;
	        }
	        mCameraDevice.setZoomChangeListener(null);
	        mCameraDevice.setErrorCallback(null);
	        CameraHolder.instance().release();
	        mCameraDevice = null;
	    }

	private void stopPreview(){
		System.out.println("============================stop preview"+mState);
		if(mCameraDevice !=null){
			saveQueue(true);
			mCameraDevice.stopPreview();
			//mCameraDevice.release();
			mServiceIsOpen = -1;
		}
	}

	public class CameraErrorCallback implements
			android.hardware.Camera.ErrorCallback {
		@Override
		public void onError(int error, android.hardware.Camera camera) {
			Log.e(TAG, "Got camera error callback. error=" + error);
			if (error == android.hardware.Camera.CAMERA_ERROR_SERVER_DIED) {
				// We are not sure about the current state of the app (in
				// preview or
				// snapshot or recording). Closing the app is better than
				// creating a
				// new Camera object.
				throw new RuntimeException("Media server died.");
			}
		}
	}

	private MediaRecorder.OnInfoListener streamingEventHandler = new MediaRecorder.OnInfoListener() {
		@Override
		public void onInfo(MediaRecorder mr, int what, int extra) {
			Log.d("TEAONLY", "MediaRecorder event = " + what);
		}
	};

	private CameraOpenErrorCallback mCameraOpenErrorCallback = new CameraOpenErrorCallback() {
		@Override
		public void onCameraDisabled(int cameraId) {
			
			  Toast.makeText(getApplicationContext(), R.string.camera_disabled,Toast.LENGTH_LONG).show();
			 
		}

		@Override
		public void onDeviceOpenFailure(int cameraId) {
			
			Toast.makeText(getApplicationContext(), R.string.cannot_connect_camera,Toast.LENGTH_LONG).show();
			 
		}

		@Override
		public void onReconnectionFailure(CameraManager mgr) {
			
			Toast.makeText(getApplicationContext(), R.string.cannot_connect_camera,Toast.LENGTH_LONG).show();
			 
		}
	};
	//通过MyBinder对象来实现指挥CameraCrashService
	public class MyBinder extends ICameraCrashService.Stub {
		WeakReference<CameraCrashService> mService;
		 
		MyBinder(CameraCrashService service) {
		             mService = new WeakReference<CameraCrashService>(service);
	       }

		@Override
		public void stopRecording() throws RemoteException {
			// TODO Auto-generated method stub
			Log.e(TAG, "Service(Airplay) stopCameraCrashService()");
//			mService.get().StopMedia();
			mThreadRunning = false;
			/*mMsgThread.interrupt();
			try {
				mMsgThread.join();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}*/
		}

		@Override
		public boolean prepareMedia() throws RemoteException {
//			return mService.get().PrepareMedia();
			return false;
		}

		@Override
		public boolean startRecording() throws RemoteException {
//			return mService.get().StartRecording();
			return false;
		}

		@Override
		public int getRecordState() throws RemoteException {
			return mService.get().mState.value() ;
		}
		@Override
		public void startPreview() throws RemoteException {
			 mService.get().StartPreview();
		}
		@Override
		public void pip(int width,int heigth){
			Log.d(TAG, "pip: we are not support for the moment");
		}
		@Override
		public void stopPreview() throws RemoteException {
			mService.get().stopPreview();
		}
	}

}
